home *** CD-ROM | disk | FTP | other *** search
/ Ultra Pack / UltraComputing Partner Applications.iso / SunLabs / tclTK / src / tk4.0 / tkWindow.c < prev    next >
C/C++ Source or Header  |  1995-06-07  |  63KB  |  2,224 lines

  1. /* 
  2.  * tkWindow.c --
  3.  *
  4.  *    This file provides basic window-manipulation procedures,
  5.  *    which are equivalent to procedures in Xlib (and even
  6.  *    invoke them) but also maintain the local Tk_Window
  7.  *    structure.
  8.  *
  9.  * Copyright (c) 1989-1994 The Regents of the University of California.
  10.  * Copyright (c) 1994-1995 Sun Microsystems, Inc.
  11.  *
  12.  * See the file "license.terms" for information on usage and redistribution
  13.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  14.  */
  15.  
  16. static char sccsid[] = "@(#) tkWindow.c 1.185 95/06/07 13:13:20";
  17.  
  18. #include "tkPort.h"
  19. #include "tkInt.h"
  20. #include "patchlevel.h"
  21.  
  22. /*
  23.  * Count of number of main windows currently open in this process.
  24.  */
  25.  
  26. int tk_NumMainWindows;
  27.  
  28. /*
  29.  * First in list of all main windows managed by this process.
  30.  */
  31.  
  32. TkMainInfo *tkMainWindowList = NULL;
  33.  
  34. /*
  35.  * List of all displays currently in use.
  36.  */
  37.  
  38. TkDisplay *tkDisplayList = NULL;
  39.  
  40. /*
  41.  * Have statics in this module been initialized?
  42.  */
  43.  
  44. static int initialized = 0;
  45.  
  46. /*
  47.  * The variables below hold several uid's that are used in many places
  48.  * in the toolkit.
  49.  */
  50.  
  51. Tk_Uid tkDisabledUid = NULL;
  52. Tk_Uid tkActiveUid = NULL;
  53. Tk_Uid tkNormalUid = NULL;
  54.  
  55. /*
  56.  * Default values for "changes" and "atts" fields of TkWindows.  Note
  57.  * that Tk always requests all events for all windows, except StructureNotify
  58.  * events on internal windows:  these events are generated internally.
  59.  */
  60.  
  61. static XWindowChanges defChanges = {
  62.     0, 0, 1, 1, 0, 0, Above
  63. };
  64. #define ALL_EVENTS_MASK \
  65.     KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask| \
  66.     EnterWindowMask|LeaveWindowMask|PointerMotionMask|ExposureMask| \
  67.     VisibilityChangeMask|FocusChangeMask|PropertyChangeMask|ColormapChangeMask
  68. static XSetWindowAttributes defAtts= {
  69.     None,            /* background_pixmap */
  70.     0,                /* background_pixel */
  71.     CopyFromParent,        /* border_pixmap */
  72.     0,                /* border_pixel */
  73.     NorthWestGravity,        /* bit_gravity */
  74.     NorthWestGravity,        /* win_gravity */
  75.     NotUseful,            /* backing_store */
  76.     (unsigned) ~0,        /* backing_planes */
  77.     0,                /* backing_pixel */
  78.     False,            /* save_under */
  79.     ALL_EVENTS_MASK,        /* event_mask */
  80.     0,                /* do_not_propagate_mask */
  81.     False,            /* override_redirect */
  82.     CopyFromParent,        /* colormap */
  83.     None            /* cursor */
  84. };
  85.  
  86. /*
  87.  * The following structure defines all of the commands supported by
  88.  * Tk, and the C procedures that execute them.
  89.  */
  90.  
  91. typedef struct {
  92.     char *name;            /* Name of command. */
  93.     int (*cmdProc) _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp,
  94.         int argc, char **argv));
  95.                 /* Command procedure. */
  96. } TkCmd;
  97.  
  98. static TkCmd commands[] = {
  99.     /*
  100.      * Commands that are part of the intrinsics:
  101.      */
  102.  
  103.     {"after",        Tk_AfterCmd},
  104.     {"bell",        Tk_BellCmd},
  105.     {"bind",        Tk_BindCmd},
  106.     {"bindtags",    Tk_BindtagsCmd},
  107.     {"clipboard",    Tk_ClipboardCmd},
  108.     {"destroy",        Tk_DestroyCmd},
  109.     {"exit",        Tk_ExitCmd},
  110.     {"fileevent",    Tk_FileeventCmd},
  111.     {"focus",        Tk_FocusCmd},
  112.     {"grab",        Tk_GrabCmd},
  113.     {"image",        Tk_ImageCmd},
  114.     {"lower",        Tk_LowerCmd},
  115.     {"option",        Tk_OptionCmd},
  116.     {"pack",        Tk_PackCmd},
  117.     {"place",        Tk_PlaceCmd},
  118.     {"raise",        Tk_RaiseCmd},
  119.     {"selection",    Tk_SelectionCmd},
  120.     {"tk",        Tk_TkCmd},
  121.     {"tkwait",        Tk_TkwaitCmd},
  122.     {"update",        Tk_UpdateCmd},
  123.     {"winfo",        Tk_WinfoCmd},
  124.     {"wm",        Tk_WmCmd},
  125.  
  126.     /*
  127.      * Widget class commands.
  128.      */
  129.     {"button",        Tk_ButtonCmd},
  130.     {"canvas",        Tk_CanvasCmd},
  131.     {"checkbutton",    Tk_CheckbuttonCmd},
  132.     {"entry",        Tk_EntryCmd},
  133.     {"frame",        Tk_FrameCmd},
  134.     {"label",        Tk_LabelCmd},
  135.     {"listbox",        Tk_ListboxCmd},
  136.     {"menu",        Tk_MenuCmd},
  137.     {"menubutton",    Tk_MenubuttonCmd},
  138.     {"message",        Tk_MessageCmd},
  139.     {"radiobutton",    Tk_RadiobuttonCmd},
  140.     {"scale",        Tk_ScaleCmd},
  141.     {"scrollbar",    Tk_ScrollbarCmd},
  142.     {"text",        Tk_TextCmd},
  143.     {"toplevel",    Tk_FrameCmd},
  144.     {(char *) NULL,    (int (*)()) NULL}
  145. };
  146.  
  147. /*
  148.  * Forward declarations to procedures defined later in this file:
  149.  */
  150.  
  151. static TkWindow    *    AllocWindow _ANSI_ARGS_((TkDisplay *dispPtr,
  152.                 int screenNum, TkWindow *parentPtr));
  153. static Tk_Window    CreateTopLevelWindow _ANSI_ARGS_((Tcl_Interp *interp,
  154.                 Tk_Window parent, char *name, char *screenName));
  155. static void        DoConfigureNotify _ANSI_ARGS_((TkWindow *winPtr));
  156. static TkDisplay *    GetScreen _ANSI_ARGS_((Tcl_Interp *interp,
  157.                 char *screenName, int *screenPtr));
  158. static int        NameWindow _ANSI_ARGS_((Tcl_Interp *interp,
  159.                 TkWindow *winPtr, TkWindow *parentPtr,
  160.                 char *name));
  161. static void        OpenIM _ANSI_ARGS_((TkDisplay *dispPtr));
  162. static void        UnlinkWindow _ANSI_ARGS_((TkWindow *winPtr));
  163.  
  164. /*
  165.  *----------------------------------------------------------------------
  166.  *
  167.  * CreateTopLevelWindow --
  168.  *
  169.  *    Make a new window that will be at top-level (its parent will
  170.  *    be the root window of a screen).
  171.  *
  172.  * Results:
  173.  *    The return value is a token for the new window, or NULL if
  174.  *    an error prevented the new window from being created.  If
  175.  *    NULL is returned, an error message will be left in
  176.  *    interp->result.
  177.  *
  178.  * Side effects:
  179.  *    A new window structure is allocated locally.  An X
  180.  *    window is NOT initially created, but will be created
  181.  *    the first time the window is mapped.
  182.  *
  183.  *----------------------------------------------------------------------
  184.  */
  185.  
  186. static Tk_Window
  187. CreateTopLevelWindow(interp, parent, name, screenName)
  188.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. */
  189.     Tk_Window parent;        /* Token for logical parent of new window
  190.                  * (used for naming, options, etc.).  May
  191.                  * be NULL. */
  192.     char *name;            /* Name for new window;  if parent is
  193.                  * non-NULL, must be unique among parent's
  194.                  * children. */
  195.     char *screenName;        /* Name of screen on which to create
  196.                  * window.  NULL means use DISPLAY environment
  197.                  * variable to determine.  Empty string means
  198.                  * use parent's screen, or DISPLAY if no
  199.                  * parent. */
  200. {
  201.     register TkWindow *winPtr;
  202.     register TkDisplay *dispPtr;
  203.     int screenId;
  204.  
  205.     if (!initialized) {
  206.     initialized = 1;
  207.     tkActiveUid = Tk_GetUid("active");
  208.     tkDisabledUid = Tk_GetUid("disabled");
  209.     tkNormalUid = Tk_GetUid("normal");
  210.  
  211.     /*
  212.      * Create built-in image types.
  213.      */
  214.     
  215.     Tk_CreateImageType(&tkBitmapImageType);
  216.     Tk_CreateImageType(&tkPhotoImageType);
  217.     
  218.     /*
  219.      * Create built-in photo image formats.
  220.      */
  221.     
  222.     Tk_CreatePhotoImageFormat(&tkImgFmtGIF);
  223.     Tk_CreatePhotoImageFormat(&tkImgFmtPPM);
  224.     }
  225.  
  226.     if ((parent != NULL) && (screenName != NULL) && (screenName[0] == '\0')) {
  227.     dispPtr = ((TkWindow *) parent)->dispPtr;
  228.     screenId = Tk_ScreenNumber(parent);
  229.     } else {
  230.     dispPtr = GetScreen(interp, screenName, &screenId);
  231.     if (dispPtr == NULL) {
  232.         return (Tk_Window) NULL;
  233.     }
  234.     }
  235.  
  236.     winPtr = AllocWindow(dispPtr, screenId, (TkWindow *) parent);
  237.  
  238.     /*
  239.      * Force the window to use a the border pixel instead of border
  240.      * pixmap.  This is needed for the case where the window doesn't
  241.      * use the default visual.  In this case, the default border is
  242.      * a pixmap inherited from the root window, which won't work because
  243.      * it will have the wrong visual.
  244.      */
  245.  
  246.     winPtr->dirtyAtts |= CWBorderPixel;
  247.  
  248.     /*
  249.      * Internal windows don't normally ask for StructureNotify events,
  250.      * since we can generate them internally.  However, for top-level
  251.      * windows we need to ask for the events because the window could
  252.      * be manipulated externally.
  253.      */
  254.  
  255.     winPtr->atts.event_mask |= StructureNotifyMask;
  256.  
  257.     /*
  258.      * (Need to set the TK_TOP_LEVEL flag immediately here;  otherwise
  259.      * Tk_DestroyWindow will core dump if it is called before the flag
  260.      * has been set.)
  261.      */
  262.  
  263.     winPtr->flags |= TK_TOP_LEVEL;
  264.     if (parent != NULL) {
  265.     if (NameWindow(interp, winPtr, (TkWindow *) parent, name) != TCL_OK) {
  266.         Tk_DestroyWindow((Tk_Window) winPtr);
  267.         return (Tk_Window) NULL;
  268.     }
  269.     }
  270.     TkWmNewWindow(winPtr);
  271.     return (Tk_Window) winPtr;
  272. }
  273.  
  274. /*
  275.  *----------------------------------------------------------------------
  276.  *
  277.  * GetScreen --
  278.  *
  279.  *    Given a string name for a display-plus-screen, find the
  280.  *    TkDisplay structure for the display and return the screen
  281.  *    number too.
  282.  *
  283.  * Results:
  284.  *    The return value is a pointer to information about the display,
  285.  *    or NULL if the display couldn't be opened.  In this case, an
  286.  *    error message is left in interp->result.  The location at
  287.  *    *screenPtr is overwritten with the screen number parsed from
  288.  *    screenName.
  289.  *
  290.  * Side effects:
  291.  *    A new connection is opened to the display if there is no
  292.  *    connection already.  A new TkDisplay data structure is also
  293.  *    setup, if necessary.
  294.  *
  295.  *----------------------------------------------------------------------
  296.  */
  297.  
  298. static TkDisplay *
  299. GetScreen(interp, screenName, screenPtr)
  300.     Tcl_Interp *interp;        /* Place to leave error message. */
  301.     char *screenName;        /* Name for screen.  NULL or empty means
  302.                  * use DISPLAY envariable. */
  303.     int *screenPtr;        /* Where to store screen number. */
  304. {
  305.     register TkDisplay *dispPtr;
  306.     char *p;
  307.     int screenId;
  308.     size_t length;
  309.  
  310.     /*
  311.      * Separate the screen number from the rest of the display
  312.      * name.  ScreenName is assumed to have the syntax
  313.      * <display>.<screen> with the dot and the screen being
  314.      * optional.
  315.      */
  316.  
  317.     if ((screenName == NULL) || (screenName[0] == '\0')) {
  318.     screenName = Tcl_GetVar2(interp, "env", "DISPLAY", TCL_GLOBAL_ONLY);
  319.     if (screenName == NULL) {
  320.         interp->result =
  321.             "no display name and no $DISPLAY environment variable";
  322.         return (TkDisplay *) NULL;
  323.     }
  324.     }
  325.     length = strlen(screenName);
  326.     screenId = 0;
  327.     p = screenName+length-1;
  328.     while (isdigit(UCHAR(*p)) && (p != screenName)) {
  329.     p--;
  330.     }
  331.     if ((*p == '.') && (p[1] != '\0')) {
  332.     length = p - screenName;
  333.     screenId = strtoul(p+1, (char **) NULL, 10);
  334.     }
  335.  
  336.     /*
  337.      * See if we already have a connection to this display.  If not,
  338.      * then open a new connection.
  339.      */
  340.  
  341.     for (dispPtr = tkDisplayList; ; dispPtr = dispPtr->nextPtr) {
  342.     if (dispPtr == NULL) {
  343.         Display *display;
  344.  
  345.         display = XOpenDisplay(screenName);
  346.         if (display == NULL) {
  347.         Tcl_AppendResult(interp, "couldn't connect to display \"",
  348.             screenName, "\"", (char *) NULL);
  349.         return (TkDisplay *) NULL;
  350.         }
  351.         dispPtr = (TkDisplay *) ckalloc(sizeof(TkDisplay));
  352.         dispPtr->display = display;
  353.         dispPtr->nextPtr = tkDisplayList;
  354.         dispPtr->name = (char *) ckalloc((unsigned) (length+1));
  355.         dispPtr->lastEventTime = CurrentTime;
  356.         strncpy(dispPtr->name, screenName, length);
  357.         dispPtr->name[length] = '\0';
  358.         dispPtr->bindInfoStale = 1;
  359.         dispPtr->numModKeyCodes = 0;
  360.         dispPtr->modKeyCodes = NULL;
  361.         OpenIM(dispPtr);
  362.         dispPtr->errorPtr = NULL;
  363.         dispPtr->deleteCount = 0;
  364.         dispPtr->commTkwin = NULL;
  365.         dispPtr->selectionInfoPtr = NULL;
  366.         dispPtr->multipleAtom = None;
  367.         dispPtr->clipWindow = NULL;
  368.         dispPtr->clipboardActive = 0;
  369.         dispPtr->clipboardAppPtr = NULL;
  370.         dispPtr->atomInit = 0;
  371.         dispPtr->cursorFont = None;
  372.         dispPtr->grabWinPtr = NULL;
  373.         dispPtr->eventualGrabWinPtr = NULL;
  374.         dispPtr->buttonWinPtr = NULL;
  375.         dispPtr->serverWinPtr = NULL;
  376.         dispPtr->firstGrabEventPtr = NULL;
  377.         dispPtr->lastGrabEventPtr = NULL;
  378.         dispPtr->grabFlags = 0;
  379.         TkInitXId(dispPtr);
  380.         dispPtr->destroyCount = 0;
  381.         dispPtr->lastDestroyRequest = 0;
  382.         dispPtr->cmapPtr = NULL;
  383.         dispPtr->focusWinPtr = NULL;
  384.         dispPtr->implicitWinPtr = NULL;
  385.         dispPtr->focusOnMapPtr = NULL;
  386.         dispPtr->forceFocus = 0;
  387.         dispPtr->stressPtr = NULL;
  388.         Tcl_InitHashTable(&dispPtr->winTable, TCL_ONE_WORD_KEYS);
  389.         tkDisplayList = dispPtr;
  390.         Tk_CreateFileHandler2(ConnectionNumber(display), TkXFileProc,
  391.             (ClientData) display);
  392.         break;
  393.     }
  394.     if ((strncmp(dispPtr->name, screenName, length) == 0)
  395.         && (dispPtr->name[length] == '\0')) {
  396.         break;
  397.     }
  398.     }
  399.     if (screenId >= ScreenCount(dispPtr->display)) {
  400.     sprintf(interp->result, "bad screen number \"%d\"", screenId);
  401.     return (TkDisplay *) NULL;
  402.     }
  403.     *screenPtr = screenId;
  404.     return dispPtr;
  405. }
  406.  
  407. /*
  408.  *----------------------------------------------------------------------
  409.  *
  410.  * TkGetDisplay --
  411.  *
  412.  *    Given an X display, TkGetDisplay returns the TkDisplay 
  413.  *      structure for the display.
  414.  *
  415.  * Results:
  416.  *    The return value is a pointer to information about the display,
  417.  *    or NULL if the display did not have a TkDisplay structure.
  418.  *
  419.  * Side effects:
  420.  *      None.
  421.  *
  422.  *----------------------------------------------------------------------
  423.  */
  424.  
  425. TkDisplay *
  426. TkGetDisplay(display)
  427.      Display *display;          /* X's display pointer */
  428. {
  429.     TkDisplay *dispPtr;
  430.  
  431.     for (dispPtr = tkDisplayList; dispPtr != NULL;
  432.         dispPtr = dispPtr->nextPtr) {
  433.     if (dispPtr->display == display) {
  434.         break;
  435.     }
  436.     }
  437.     return dispPtr;
  438. }
  439.  
  440. /*
  441.  *--------------------------------------------------------------
  442.  *
  443.  * AllocWindow --
  444.  *
  445.  *    This procedure creates and initializes a TkWindow structure.
  446.  *
  447.  * Results:
  448.  *    The return value is a pointer to the new window.
  449.  *
  450.  * Side effects:
  451.  *    A new window structure is allocated and all its fields are
  452.  *    initialized.
  453.  *
  454.  *--------------------------------------------------------------
  455.  */
  456.  
  457. static TkWindow *
  458. AllocWindow(dispPtr, screenNum, parentPtr)
  459.     TkDisplay *dispPtr;        /* Display associated with new window. */
  460.     int screenNum;        /* Index of screen for new window. */
  461.     TkWindow *parentPtr;    /* Parent from which this window should
  462.                  * inherit visual information.  NULL means
  463.                  * use screen defaults instead of
  464.                  * inheriting. */
  465. {
  466.     register TkWindow *winPtr;
  467.  
  468.     winPtr = (TkWindow *) ckalloc(sizeof(TkWindow));
  469.     winPtr->display = dispPtr->display;
  470.     winPtr->dispPtr = dispPtr;
  471.     winPtr->screenNum = screenNum;
  472.     if ((parentPtr != NULL) && (parentPtr->display == winPtr->display)
  473.         && (parentPtr->screenNum == winPtr->screenNum)) {
  474.     winPtr->visual = parentPtr->visual;
  475.     winPtr->depth = parentPtr->depth;
  476.     } else {
  477.     winPtr->visual = DefaultVisual(dispPtr->display, screenNum);
  478.     winPtr->depth = DefaultDepth(dispPtr->display, screenNum);
  479.     }
  480.     winPtr->window = None;
  481.     winPtr->childList = NULL;
  482.     winPtr->lastChildPtr = NULL;
  483.     winPtr->parentPtr = NULL;
  484.     winPtr->nextPtr = NULL;
  485.     winPtr->mainPtr = NULL;
  486.     winPtr->pathName = NULL;
  487.     winPtr->nameUid = NULL;
  488.     winPtr->classUid = NULL;
  489.     winPtr->changes = defChanges;
  490.     winPtr->dirtyChanges = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
  491.     winPtr->atts = defAtts;
  492.     if ((parentPtr != NULL) && (parentPtr->display == winPtr->display)
  493.         && (parentPtr->screenNum == winPtr->screenNum)) {
  494.     winPtr->atts.colormap = parentPtr->atts.colormap;
  495.     } else {
  496.     winPtr->atts.colormap = DefaultColormap(dispPtr->display, screenNum);
  497.     }
  498.     winPtr->dirtyAtts = CWEventMask|CWColormap|CWBitGravity;
  499.     winPtr->flags = 0;
  500.     winPtr->handlerList = NULL;
  501. #ifdef TK_USE_INPUT_METHODS
  502.     winPtr->inputContext = NULL;
  503. #endif /* TK_USE_INPUT_METHODS */
  504.     winPtr->tagPtr = NULL;
  505.     winPtr->numTags = 0;
  506.     winPtr->optionLevel = -1;
  507.     winPtr->selHandlerList = NULL;
  508.     winPtr->geomMgrPtr = NULL;
  509.     winPtr->geomData = NULL;
  510.     winPtr->reqWidth = winPtr->reqHeight = 1;
  511.     winPtr->internalBorderWidth = 0;
  512.     winPtr->wmInfoPtr = NULL;
  513.  
  514.     return winPtr;
  515. }
  516.  
  517. /*
  518.  *----------------------------------------------------------------------
  519.  *
  520.  * NameWindow --
  521.  *
  522.  *    This procedure is invoked to give a window a name and insert
  523.  *    the window into the hierarchy associated with a particular
  524.  *    application.
  525.  *
  526.  * Results:
  527.  *    A standard Tcl return value.
  528.  *
  529.  * Side effects:
  530.  *      See above.
  531.  *
  532.  *----------------------------------------------------------------------
  533.  */
  534.  
  535. static int
  536. NameWindow(interp, winPtr, parentPtr, name)
  537.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. */
  538.     register TkWindow *winPtr;    /* Window that is to be named and inserted. */
  539.     TkWindow *parentPtr;    /* Pointer to logical parent for winPtr
  540.                  * (used for naming, options, etc.). */
  541.     char *name;            /* Name for winPtr;   must be unique among
  542.                  * parentPtr's children. */
  543. {
  544. #define FIXED_SIZE 200
  545.     char staticSpace[FIXED_SIZE];
  546.     char *pathName;
  547.     int new;
  548.     Tcl_HashEntry *hPtr;
  549.     int length1, length2;
  550.  
  551.     /*
  552.      * Setup all the stuff except name right away, then do the name stuff
  553.      * last.  This is so that if the name stuff fails, everything else
  554.      * will be properly initialized (needed to destroy the window cleanly
  555.      * after the naming failure).
  556.      */
  557.     winPtr->parentPtr = parentPtr;
  558.     winPtr->nextPtr = NULL;
  559.     if (parentPtr->childList == NULL) {
  560.     parentPtr->childList = winPtr;
  561.     } else {
  562.     parentPtr->lastChildPtr->nextPtr = winPtr;
  563.     }
  564.     parentPtr->lastChildPtr = winPtr;
  565.     winPtr->mainPtr = parentPtr->mainPtr;
  566.     winPtr->mainPtr->refCount++;
  567.     winPtr->nameUid = Tk_GetUid(name);
  568.  
  569.     /*
  570.      * Don't permit names that start with an upper-case letter:  this
  571.      * will just cause confusion with class names in the option database.
  572.      */
  573.  
  574.     if (isupper(UCHAR(name[0]))) {
  575.     Tcl_AppendResult(interp,
  576.         "window name starts with an upper-case letter: \"",
  577.         name, "\"", (char *) NULL);
  578.     return TCL_ERROR;
  579.     }
  580.  
  581.     /*
  582.      * To permit names of arbitrary length, must be prepared to malloc
  583.      * a buffer to hold the new path name.  To run fast in the common
  584.      * case where names are short, use a fixed-size buffer on the
  585.      * stack.
  586.      */
  587.  
  588.     length1 = strlen(parentPtr->pathName);
  589.     length2 = strlen(name);
  590.     if ((length1+length2+2) <= FIXED_SIZE) {
  591.     pathName = staticSpace;
  592.     } else {
  593.     pathName = (char *) ckalloc((unsigned) (length1+length2+2));
  594.     }
  595.     if (length1 == 1) {
  596.     pathName[0] = '.';
  597.     strcpy(pathName+1, name);
  598.     } else {
  599.     strcpy(pathName, parentPtr->pathName);
  600.     pathName[length1] = '.';
  601.     strcpy(pathName+length1+1, name);
  602.     }
  603.     hPtr = Tcl_CreateHashEntry(&parentPtr->mainPtr->nameTable, pathName, &new);
  604.     if (pathName != staticSpace) {
  605.     ckfree(pathName);
  606.     }
  607.     if (!new) {
  608.     Tcl_AppendResult(interp, "window name \"", name,
  609.         "\" already exists in parent", (char *) NULL);
  610.     return TCL_ERROR;
  611.     }
  612.     Tcl_SetHashValue(hPtr, winPtr);
  613.     winPtr->pathName = Tcl_GetHashKey(&parentPtr->mainPtr->nameTable, hPtr);
  614.     return TCL_OK;
  615. }
  616.  
  617. /*
  618.  *----------------------------------------------------------------------
  619.  *
  620.  * Tk_CreateMainWindow --
  621.  *
  622.  *    Make a new main window.  A main window is a special kind of
  623.  *    top-level window used as the outermost window in an
  624.  *    application.
  625.  *
  626.  * Results:
  627.  *    The return value is a token for the new window, or NULL if
  628.  *    an error prevented the new window from being created.  If
  629.  *    NULL is returned, an error message will be left in
  630.  *    interp->result.
  631.  *
  632.  * Side effects:
  633.  *    A new window structure is allocated locally;  "interp" is
  634.  *    associated with the window and registered for "send" commands
  635.  *    under "baseName".  BaseName may be extended with an instance
  636.  *    number in the form "#2" if necessary to make it globally
  637.  *    unique.  Tk-related commands are bound into interp.  The main
  638.  *    window becomes a "toplevel" widget and its X window will be
  639.  *    created and mapped as an idle handler.
  640.  *
  641.  *----------------------------------------------------------------------
  642.  */
  643.  
  644. Tk_Window
  645. Tk_CreateMainWindow(interp, screenName, baseName, className)
  646.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. */
  647.     char *screenName;        /* Name of screen on which to create
  648.                  * window.  Empty or NULL string means
  649.                  * use DISPLAY environment variable. */
  650.     char *baseName;        /* Base name for application;  usually of the
  651.                  * form "prog instance". */
  652.     char *className;        /* Class to use for application (same as class
  653.                  * for main window). */
  654. {
  655.     Tk_Window tkwin;
  656.     int dummy;
  657.     Tcl_HashEntry *hPtr;
  658.     register TkMainInfo *mainPtr;
  659.     register TkWindow *winPtr;
  660.     register TkCmd *cmdPtr;
  661.     char *libDir;
  662.     static char *argv[] = {(char *) NULL};
  663.  
  664.     /*
  665.      * Panic if someone updated the TkWindow structure without
  666.      * also updating the Tk_FakeWin structure (or vice versa).
  667.      */
  668.  
  669.     if (sizeof(TkWindow) != sizeof(Tk_FakeWin)) {
  670.     panic("TkWindow and Tk_FakeWin are not the same size");
  671.     }
  672.  
  673.     /*
  674.      * Create the basic TkWindow structure.
  675.      */
  676.  
  677.     tkwin = CreateTopLevelWindow(interp, (Tk_Window) NULL, baseName,
  678.         screenName);
  679.     if (tkwin == NULL) {
  680.     return NULL;
  681.     }
  682.  
  683.     /*
  684.      * Create the TkMainInfo structure for this application, and set
  685.      * up name-related information for the new window.
  686.      */
  687.  
  688.     winPtr = (TkWindow *) tkwin;
  689.     mainPtr = (TkMainInfo *) ckalloc(sizeof(TkMainInfo));
  690.     mainPtr->winPtr = winPtr;
  691.     mainPtr->refCount = 1;
  692.     mainPtr->interp = interp;
  693.     Tcl_InitHashTable(&mainPtr->nameTable, TCL_STRING_KEYS);
  694.     mainPtr->bindingTable = Tk_CreateBindingTable(interp);
  695.     mainPtr->curDispPtr = NULL;
  696.     mainPtr->curScreenIndex = -1;
  697.     mainPtr->bindingDepth = 0;
  698.     mainPtr->focusPtr = NULL;
  699.     mainPtr->focusSerial = 0;
  700.     mainPtr->lastFocusPtr = NULL;
  701.     mainPtr->optionRootPtr = NULL;
  702.     Tcl_InitHashTable(&mainPtr->imageTable, TCL_STRING_KEYS);
  703.     mainPtr->strictMotif = 0;
  704.     if (Tcl_LinkVar(interp, "tk_strictMotif", (char *) &mainPtr->strictMotif,
  705.         TCL_LINK_BOOLEAN) != TCL_OK) {
  706.     Tcl_ResetResult(interp);
  707.     }
  708.     mainPtr->nextPtr = tkMainWindowList;
  709.     tkMainWindowList = mainPtr;
  710.     winPtr->mainPtr = mainPtr;
  711.     hPtr = Tcl_CreateHashEntry(&mainPtr->nameTable, ".", &dummy);
  712.     Tcl_SetHashValue(hPtr, winPtr);
  713.     winPtr->pathName = Tcl_GetHashKey(&mainPtr->nameTable, hPtr);
  714.  
  715.     /*
  716.      * Register the interpreter for "send" purposes.
  717.      */
  718.  
  719.     winPtr->nameUid = Tk_GetUid(Tk_SetAppName(tkwin, baseName));
  720.  
  721.     /*
  722.      * Bind in Tk's commands.
  723.      */
  724.  
  725.     for (cmdPtr = commands; cmdPtr->name != NULL; cmdPtr++) {
  726.     Tcl_CreateCommand(interp, cmdPtr->name, cmdPtr->cmdProc,
  727.         (ClientData) tkwin, (void (*)()) NULL);
  728.     }
  729.     Tcl_CallWhenDeleted(interp, TkEventCleanupProc, (ClientData) NULL);
  730.  
  731.     /*
  732.      * Set variables for the intepreter.
  733.      */
  734.  
  735.     if (Tcl_GetVar(interp, "tk_library", TCL_GLOBAL_ONLY) == NULL) {
  736.     /*
  737.      * A library directory hasn't already been set, so figure out
  738.      * which one to use.
  739.      */
  740.  
  741.     libDir = getenv("TK_LIBRARY");
  742.     if (libDir == NULL) {
  743.         libDir = TK_LIBRARY;
  744.     }
  745.     Tcl_SetVar(interp, "tk_library", libDir, TCL_GLOBAL_ONLY);
  746.     }
  747.     Tcl_SetVar(interp, "tk_patchLevel", TK_PATCH_LEVEL, TCL_GLOBAL_ONLY);
  748.     Tcl_SetVar(interp, "tk_version", TK_VERSION, TCL_GLOBAL_ONLY);
  749.  
  750.     /*
  751.      * Make the main window into a toplevel widget, and give it an initial
  752.      * requested size.
  753.      */
  754.  
  755.     Tk_SetClass(tkwin, className);
  756.     if (TkInitFrame(interp, tkwin, 1, 0, argv) == NULL) {
  757.     return NULL;
  758.     }
  759.     Tk_GeometryRequest(tkwin, 200, 200);
  760.  
  761.     tk_NumMainWindows++;
  762.     return tkwin;
  763. }
  764.  
  765. /*
  766.  *----------------------------------------------------------------------
  767.  *
  768.  * Tk_Init --
  769.  *
  770.  *    This procedure is typically invoked by Tcl_AppInit procedures
  771.  *    to perform additional Tk initialization for a Tcl interpreter,
  772.  *    such as sourcing the "tk.tcl" script.
  773.  *
  774.  * Results:
  775.  *    Returns a standard Tcl completion code and sets interp->result
  776.  *    if there is an error.
  777.  *
  778.  * Side effects:
  779.  *    Depends on what's in the tk.tcl script.
  780.  *
  781.  *----------------------------------------------------------------------
  782.  */
  783.  
  784. int
  785. Tk_Init(interp)
  786.     Tcl_Interp *interp;        /* Interpreter to initialize. */
  787. {
  788.     static char initCmd[] =
  789.     "if [file exists $tk_library/tk.tcl] {\n\
  790.         source $tk_library/tk.tcl\n\
  791.     } else {\n\
  792.         set msg \"can't find $tk_library/tk.tcl; perhaps you \"\n\
  793.         append msg \"need to\\ninstall Tk or set your TK_LIBRARY \"\n\
  794.         append msg \"environment variable?\"\n\
  795.         error $msg\n\
  796.     }";
  797.  
  798.     return Tcl_Eval(interp, initCmd);
  799. }
  800.  
  801. /*
  802.  *--------------------------------------------------------------
  803.  *
  804.  * Tk_CreateWindow --
  805.  *
  806.  *    Create a new internal or top-level window as a child of an
  807.  *    existing window.
  808.  *
  809.  * Results:
  810.  *    The return value is a token for the new window.  This
  811.  *    is not the same as X's token for the window.  If an error
  812.  *    occurred in creating the window (e.g. no such display or
  813.  *    screen), then an error message is left in interp->result and
  814.  *    NULL is returned.
  815.  *
  816.  * Side effects:
  817.  *    A new window structure is allocated locally.  An X
  818.  *    window is not initially created, but will be created
  819.  *    the first time the window is mapped.
  820.  *
  821.  *--------------------------------------------------------------
  822.  */
  823.  
  824. Tk_Window
  825. Tk_CreateWindow(interp, parent, name, screenName)
  826.     Tcl_Interp *interp;        /* Interpreter to use for error reporting.
  827.                  * Interp->result is assumed to be
  828.                  * initialized by the caller. */
  829.     Tk_Window parent;        /* Token for parent of new window. */
  830.     char *name;            /* Name for new window.  Must be unique
  831.                  * among parent's children. */
  832.     char *screenName;        /* If NULL, new window will be internal on
  833.                  * same screen as its parent.  If non-NULL,
  834.                  * gives name of screen on which to create
  835.                  * new window;  window will be a top-level
  836.                  * window. */
  837. {
  838.     TkWindow *parentPtr = (TkWindow *) parent;
  839.     TkWindow *winPtr;
  840.  
  841.     if (screenName == NULL) {
  842.     winPtr = AllocWindow(parentPtr->dispPtr, parentPtr->screenNum,
  843.         parentPtr);
  844.     if (NameWindow(interp, winPtr, parentPtr, name) != TCL_OK) {
  845.         Tk_DestroyWindow((Tk_Window) winPtr);
  846.         return NULL;
  847.     } else {
  848.       return (Tk_Window) winPtr;
  849.     }
  850.     } else {
  851.     return CreateTopLevelWindow(interp, parent, name, screenName);
  852.     }
  853. }
  854.  
  855. /*
  856.  *----------------------------------------------------------------------
  857.  *
  858.  * Tk_CreateWindowFromPath --
  859.  *
  860.  *    This procedure is similar to Tk_CreateWindow except that
  861.  *    it uses a path name to create the window, rather than a
  862.  *    parent and a child name.
  863.  *
  864.  * Results:
  865.  *    The return value is a token for the new window.  This
  866.  *    is not the same as X's token for the window.  If an error
  867.  *    occurred in creating the window (e.g. no such display or
  868.  *    screen), then an error message is left in interp->result and
  869.  *    NULL is returned.
  870.  *
  871.  * Side effects:
  872.  *    A new window structure is allocated locally.  An X
  873.  *    window is not initially created, but will be created
  874.  *    the first time the window is mapped.
  875.  *
  876.  *----------------------------------------------------------------------
  877.  */
  878.  
  879. Tk_Window
  880. Tk_CreateWindowFromPath(interp, tkwin, pathName, screenName)
  881.     Tcl_Interp *interp;        /* Interpreter to use for error reporting.
  882.                  * Interp->result is assumed to be
  883.                  * initialized by the caller. */
  884.     Tk_Window tkwin;        /* Token for any window in application
  885.                  * that is to contain new window. */
  886.     char *pathName;        /* Path name for new window within the
  887.                  * application of tkwin.  The parent of
  888.                  * this window must already exist, but
  889.                  * the window itself must not exist. */
  890.     char *screenName;        /* If NULL, new window will be on same
  891.                  * screen as its parent.  If non-NULL,
  892.                  * gives name of screen on which to create
  893.                  * new window;  window will be a top-level
  894.                  * window. */
  895. {
  896. #define FIXED_SPACE 5
  897.     char fixedSpace[FIXED_SPACE+1];
  898.     char *p;
  899.     Tk_Window parent;
  900.     int numChars;
  901.  
  902.     /*
  903.      * Strip the parent's name out of pathName (it's everything up
  904.      * to the last dot).  There are two tricky parts: (a) must
  905.      * copy the parent's name somewhere else to avoid modifying
  906.      * the pathName string (for large names, space for the copy
  907.      * will have to be malloc'ed);  (b) must special-case the
  908.      * situation where the parent is ".".
  909.      */
  910.  
  911.     p = strrchr(pathName, '.');
  912.     if (p == NULL) {
  913.     Tcl_AppendResult(interp, "bad window path name \"", pathName,
  914.         "\"", (char *) NULL);
  915.     return NULL;
  916.     }
  917.     numChars = p-pathName;
  918.     if (numChars > FIXED_SPACE) {
  919.     p = (char *) ckalloc((unsigned) (numChars+1));
  920.     } else {
  921.     p = fixedSpace;
  922.     }
  923.     if (numChars == 0) {
  924.     *p = '.';
  925.     p[1] = '\0';
  926.     } else {
  927.     strncpy(p, pathName, (size_t) numChars);
  928.     p[numChars] = '\0';
  929.     }
  930.  
  931.     /*
  932.      * Find the parent window.
  933.      */
  934.  
  935.     parent = Tk_NameToWindow(interp, p, tkwin);
  936.     if (p != fixedSpace) {
  937.     ckfree(p);
  938.     }
  939.     if (parent == NULL) {
  940.     return NULL;
  941.     }
  942.  
  943.     /*
  944.      * Create the window.
  945.      */
  946.  
  947.     if (screenName == NULL) {
  948.     TkWindow *parentPtr = (TkWindow *) parent;
  949.     TkWindow *winPtr;
  950.  
  951.     winPtr = AllocWindow(parentPtr->dispPtr, parentPtr->screenNum,
  952.         parentPtr);
  953.     if (NameWindow(interp, winPtr, parentPtr, pathName+numChars+1)
  954.         != TCL_OK) {
  955.         Tk_DestroyWindow((Tk_Window) winPtr);
  956.         return NULL;
  957.     } else {
  958.         return (Tk_Window) winPtr;
  959.     }
  960.     } else {
  961.     return CreateTopLevelWindow(interp, parent, pathName+numChars+1,
  962.         screenName);
  963.     }
  964. }
  965.  
  966. /*
  967.  *--------------------------------------------------------------
  968.  *
  969.  * Tk_DestroyWindow --
  970.  *
  971.  *    Destroy an existing window.  After this call, the caller
  972.  *    should never again use the token.
  973.  *
  974.  * Results:
  975.  *    None.
  976.  *
  977.  * Side effects:
  978.  *    The window is deleted, along with all of its children.
  979.  *    Relevant callback procedures are invoked.
  980.  *
  981.  *--------------------------------------------------------------
  982.  */
  983.  
  984. void
  985. Tk_DestroyWindow(tkwin)
  986.     Tk_Window tkwin;        /* Window to destroy. */
  987. {
  988.     TkWindow *winPtr = (TkWindow *) tkwin;
  989.     TkDisplay *dispPtr = winPtr->dispPtr;
  990.     XEvent event;
  991.  
  992.     if (winPtr->flags & TK_ALREADY_DEAD) {
  993.     /*
  994.      * A destroy event binding caused the window to be destroyed
  995.      * again.  Ignore the request.
  996.      */
  997.  
  998.     return;
  999.     }
  1000.     winPtr->flags |= TK_ALREADY_DEAD;
  1001.  
  1002.     /*
  1003.      * Some cleanup needs to be done immediately, rather than later,
  1004.      * because it needs information that will be destoyed before we
  1005.      * get to the main cleanup point.  For example, TkFocusDeadWindow
  1006.      * needs to access the parentPtr field from a window, but if
  1007.      * a Destroy event handler deletes the window's parent this
  1008.      * field will be NULL before the main cleanup point is reached.
  1009.      */
  1010.  
  1011.     TkFocusDeadWindow(winPtr);
  1012.  
  1013.     /*
  1014.      * If this is a main window, remove it from the list of main
  1015.      * windows.  This needs to be done now (rather than later with
  1016.      * all the other main window cleanup) to handle situations where
  1017.      * a destroy binding for a window calls "exit".  In this case
  1018.      * the child window cleanup isn't complete when exit is called,
  1019.      * so the reference count of its application doesn't go to zero
  1020.      * when exit calls Tk_DestroyWindow on ".", so the main window
  1021.      * doesn't get removed from the list and exit loops infinitely.
  1022.      * Even worse, if "destroy ." is called by the destroy binding
  1023.      * before calling "exit", "exit" will attempt to destroy
  1024.      * mainPtr->winPtr, which no longer exists, and there may be a
  1025.      * core dump.
  1026.      */
  1027.  
  1028.     if (winPtr->mainPtr->winPtr == winPtr) {
  1029.     if (tkMainWindowList == winPtr->mainPtr) {
  1030.         tkMainWindowList = winPtr->mainPtr->nextPtr;
  1031.     } else {
  1032.         TkMainInfo *prevPtr;
  1033.  
  1034.         for (prevPtr = tkMainWindowList;
  1035.             prevPtr->nextPtr != winPtr->mainPtr;
  1036.             prevPtr = prevPtr->nextPtr) {
  1037.         /* Empty loop body. */
  1038.         }
  1039.         prevPtr->nextPtr = winPtr->mainPtr->nextPtr;
  1040.     }
  1041.     tk_NumMainWindows--;
  1042.     }
  1043.  
  1044.     /*
  1045.      * Recursively destroy children.
  1046.      */
  1047.  
  1048.     dispPtr->destroyCount++;
  1049.     while (winPtr->childList != NULL) {
  1050.     TkWindow *childPtr;
  1051.  
  1052.     childPtr = winPtr->childList;
  1053.     childPtr->flags |= TK_PARENT_DESTROYED;
  1054.     Tk_DestroyWindow((Tk_Window) childPtr);
  1055.     if (winPtr->childList == childPtr) {
  1056.         /*
  1057.          * The child didn't remove itself from the child list, so
  1058.          * let's remove it here.  This can happen in some strange
  1059.          * conditions, such as when a Delete event handler for a
  1060.          * window deletes the window's parent.
  1061.          */
  1062.  
  1063.         winPtr->childList = childPtr->nextPtr;
  1064.         childPtr->parentPtr = NULL;
  1065.     }
  1066.     }
  1067.  
  1068.     /*
  1069.      * Generate a DestroyNotify event.  In order for the DestroyNotify
  1070.      * event to be processed correctly, need to make sure the window
  1071.      * exists.  This is a bit of a kludge, and may be unnecessarily
  1072.      * expensive, but without it no event handlers will get called for
  1073.      * windows that don't exist yet.
  1074.      *
  1075.      * Note: if the window's pathName is NULL it means that the window
  1076.      * was not successfully initialized in the first place, so we should
  1077.      * not make the window exist or generate the event.
  1078.      */
  1079.  
  1080.     if (winPtr->pathName != NULL) {
  1081.     if (winPtr->window == None) {
  1082.         Tk_MakeWindowExist(tkwin);
  1083.     }
  1084.     event.type = DestroyNotify;
  1085.     event.xdestroywindow.serial =
  1086.         LastKnownRequestProcessed(winPtr->display);
  1087.     event.xdestroywindow.send_event = False;
  1088.     event.xdestroywindow.display = winPtr->display;
  1089.     event.xdestroywindow.event = winPtr->window;
  1090.     event.xdestroywindow.window = winPtr->window;
  1091.     Tk_HandleEvent(&event);
  1092.     }
  1093.  
  1094.     /*
  1095.      * Cleanup the data structures associated with this window.  First,
  1096.      * destroy the X window.  If the parent has already been destroyed
  1097.      * and this isn't a top-level window, then this window will be
  1098.      * destroyed implicitly when the parent's X window is destroyed;
  1099.      * it's much faster not to do an explicit destroy of this X window.
  1100.      */
  1101.  
  1102.     if (winPtr->window != None) {
  1103.     if ((winPtr->flags & TK_TOP_LEVEL)
  1104.         || !(winPtr->flags & TK_PARENT_DESTROYED)) {
  1105.         dispPtr->lastDestroyRequest = NextRequest(winPtr->display);
  1106.         XDestroyWindow(winPtr->display, winPtr->window);
  1107.     }
  1108.     TkFreeWindowId(dispPtr, winPtr->window);
  1109.     Tcl_DeleteHashEntry(Tcl_FindHashEntry(&dispPtr->winTable,
  1110.         (char *) winPtr->window));
  1111.     winPtr->window = None;
  1112.     }
  1113.     dispPtr->destroyCount--;
  1114.     UnlinkWindow(winPtr);
  1115.     TkEventDeadWindow(winPtr);
  1116. #ifdef TK_USE_INPUT_METHODS
  1117.     if (winPtr->inputContext != NULL) {
  1118.     XDestroyIC(winPtr->inputContext);
  1119.     }
  1120. #endif /* TK_USE_INPUT_METHODS */
  1121.     if (winPtr->tagPtr != NULL) {
  1122.     TkFreeBindingTags(winPtr);
  1123.     }
  1124.     TkOptionDeadWindow(winPtr);
  1125.     TkSelDeadWindow(winPtr);
  1126.     if (winPtr->flags & TK_TOP_LEVEL) {
  1127.     TkWmDeadWindow(winPtr);
  1128.     }
  1129.     TkGrabDeadWindow(winPtr);
  1130.     if (winPtr->mainPtr != NULL) {
  1131.     if (winPtr->pathName != NULL) {
  1132.         Tk_DeleteAllBindings(winPtr->mainPtr->bindingTable,
  1133.             (ClientData) winPtr->pathName);
  1134.         Tcl_DeleteHashEntry(Tcl_FindHashEntry(&winPtr->mainPtr->nameTable,
  1135.             winPtr->pathName));
  1136.     }
  1137.     winPtr->mainPtr->refCount--;
  1138.     if (winPtr->mainPtr->refCount == 0) {
  1139.         register TkCmd *cmdPtr;
  1140.  
  1141.         /*
  1142.          * We just deleted the last window in the application.  Delete
  1143.          * the TkMainInfo structure too and replace all of Tk's commands
  1144.          * with dummy commands that return errors (except don't replace
  1145.          * the "exit" command, since it may be needed for the application
  1146.          * to exit).  Also delete the "send" command to unregister the
  1147.          * interpreter.
  1148.          */
  1149.  
  1150.         for (cmdPtr = commands; cmdPtr->name != NULL; cmdPtr++) {
  1151.         if (cmdPtr->cmdProc != Tk_ExitCmd) {
  1152.             Tcl_CreateCommand(winPtr->mainPtr->interp, cmdPtr->name,
  1153.                 TkDeadAppCmd, (ClientData) NULL,
  1154.                 (void (*)()) NULL);
  1155.         }
  1156.         }
  1157.         Tcl_CreateCommand(winPtr->mainPtr->interp, "send",
  1158.             TkDeadAppCmd, (ClientData) NULL, (void (*)()) NULL);
  1159.         Tcl_DeleteHashTable(&winPtr->mainPtr->nameTable);
  1160.         Tk_DeleteBindingTable(winPtr->mainPtr->bindingTable);
  1161.         TkDeleteAllImages(winPtr->mainPtr);
  1162.         Tcl_UnlinkVar(winPtr->mainPtr->interp, "tk_strictMotif");
  1163.         ckfree((char *) winPtr->mainPtr);
  1164.     }
  1165.     }
  1166.     ckfree((char *) winPtr);
  1167. }
  1168.  
  1169. /*
  1170.  *--------------------------------------------------------------
  1171.  *
  1172.  * Tk_MapWindow --
  1173.  *
  1174.  *    Map a window within its parent.  This may require the
  1175.  *    window and/or its parents to actually be created.
  1176.  *
  1177.  * Results:
  1178.  *    None.
  1179.  *
  1180.  * Side effects:
  1181.  *    The given window will be mapped.  Windows may also
  1182.  *    be created.
  1183.  *
  1184.  *--------------------------------------------------------------
  1185.  */
  1186.  
  1187. void
  1188. Tk_MapWindow(tkwin)
  1189.     Tk_Window tkwin;        /* Token for window to map. */
  1190. {
  1191.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1192.     XEvent event;
  1193.  
  1194.     if (winPtr->flags & TK_MAPPED) {
  1195.     return;
  1196.     }
  1197.     if (winPtr->window == None) {
  1198.     Tk_MakeWindowExist(tkwin);
  1199.     }
  1200.     if (winPtr->flags & TK_TOP_LEVEL) {
  1201.     /*
  1202.      * Lots of special processing has to be done for top-level
  1203.      * windows.  Let tkWm.c handle everything itself.
  1204.      */
  1205.  
  1206.     TkWmMapWindow(winPtr);
  1207.     return;
  1208.     }
  1209.     winPtr->flags |= TK_MAPPED;
  1210.     XMapWindow(winPtr->display, winPtr->window);
  1211.     event.type = MapNotify;
  1212.     event.xmap.serial = LastKnownRequestProcessed(winPtr->display);
  1213.     event.xmap.send_event = False;
  1214.     event.xmap.display = winPtr->display;
  1215.     event.xmap.event = winPtr->window;
  1216.     event.xmap.window = winPtr->window;
  1217.     event.xmap.override_redirect = winPtr->atts.override_redirect;
  1218.     Tk_HandleEvent(&event);
  1219. }
  1220.  
  1221. /*
  1222.  *--------------------------------------------------------------
  1223.  *
  1224.  * Tk_MakeWindowExist --
  1225.  *
  1226.  *    Ensure that a particular window actually exists.  This
  1227.  *    procedure shouldn't normally need to be invoked from
  1228.  *    outside the Tk package, but may be needed if someone
  1229.  *    wants to manipulate a window before mapping it.
  1230.  *
  1231.  * Results:
  1232.  *    None.
  1233.  *
  1234.  * Side effects:
  1235.  *    When the procedure returns, the X window associated with
  1236.  *    tkwin is guaranteed to exist.  This may require the
  1237.  *    window's ancestors to be created also.
  1238.  *
  1239.  *--------------------------------------------------------------
  1240.  */
  1241.  
  1242. void
  1243. Tk_MakeWindowExist(tkwin)
  1244.     Tk_Window tkwin;        /* Token for window. */
  1245. {
  1246.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1247.     TkWindow *winPtr2;
  1248.     Window parent;
  1249.     Tcl_HashEntry *hPtr;
  1250.     int new;
  1251.  
  1252.     if (winPtr->window != None) {
  1253.     return;
  1254.     }
  1255.  
  1256.     if ((winPtr->parentPtr == NULL) || (winPtr->flags & TK_TOP_LEVEL)) {
  1257.     parent = XRootWindow(winPtr->display, winPtr->screenNum);
  1258.     } else {
  1259.     if (winPtr->parentPtr->window == None) {
  1260.         Tk_MakeWindowExist((Tk_Window) winPtr->parentPtr);
  1261.     }
  1262.     parent = winPtr->parentPtr->window;
  1263.     }
  1264.  
  1265.     winPtr->window = XCreateWindow(winPtr->display, parent,
  1266.         winPtr->changes.x, winPtr->changes.y,
  1267.         (unsigned) winPtr->changes.width,
  1268.         (unsigned) winPtr->changes.height,
  1269.         (unsigned) winPtr->changes.border_width, winPtr->depth,
  1270.         InputOutput, winPtr->visual, winPtr->dirtyAtts,
  1271.         &winPtr->atts);
  1272.     hPtr = Tcl_CreateHashEntry(&winPtr->dispPtr->winTable,
  1273.         (char *) winPtr->window, &new);
  1274.     Tcl_SetHashValue(hPtr, winPtr);
  1275.     winPtr->dirtyAtts = 0;
  1276.     winPtr->dirtyChanges = 0;
  1277. #ifdef TK_USE_INPUT_METHODS
  1278.     winPtr->inputContext = NULL;
  1279. #endif /* TK_USE_INPUT_METHODS */
  1280.  
  1281.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1282.     /*
  1283.      * If any siblings higher up in the stacking order have already
  1284.      * been created then move this window to its rightful position
  1285.      * in the stacking order.
  1286.      *
  1287.      * NOTE: this code ignores any changes anyone might have made
  1288.      * to the sibling and stack_mode field of the window's attributes,
  1289.      * so it really isn't safe for these to be manipulated except
  1290.      * by calling Tk_RestackWindow.
  1291.      */
  1292.  
  1293.     for (winPtr2 = winPtr->nextPtr; winPtr2 != NULL;
  1294.         winPtr2 = winPtr2->nextPtr) {
  1295.         if ((winPtr2->window != None) && !(winPtr2->flags & TK_TOP_LEVEL)) {
  1296.         XWindowChanges changes;
  1297.         changes.sibling = winPtr2->window;
  1298.         changes.stack_mode = Below;
  1299.         XConfigureWindow(winPtr->display, winPtr->window,
  1300.             CWSibling|CWStackMode, &changes);
  1301.         break;
  1302.         }
  1303.     }
  1304.  
  1305.     /*
  1306.      * If this window has a different colormap than its parent, add
  1307.      * the window to the WM_COLORMAP_WINDOWS property for its top-level.
  1308.      */
  1309.  
  1310.     if ((winPtr->parentPtr != NULL) &&
  1311.         (winPtr->atts.colormap != winPtr->parentPtr->atts.colormap)) {
  1312.         TkWmAddToColormapWindows(winPtr);
  1313.     }
  1314.     }
  1315.  
  1316.     /*
  1317.      * Issue a ConfigureNotify event if there were deferred configuration
  1318.      * changes (but skip it if the window is being deleted;  the
  1319.      * ConfigureNotify event could cause problems if we're being called
  1320.      * from Tk_DestroyWindow under some conditions).
  1321.      */
  1322.  
  1323.     if ((winPtr->flags & TK_NEED_CONFIG_NOTIFY)
  1324.         && !(winPtr->flags & TK_ALREADY_DEAD)){
  1325.     winPtr->flags &= ~TK_NEED_CONFIG_NOTIFY;
  1326.     DoConfigureNotify(winPtr);
  1327.     }
  1328. }
  1329.  
  1330. /*
  1331.  *--------------------------------------------------------------
  1332.  *
  1333.  * Tk_UnmapWindow, etc. --
  1334.  *
  1335.  *    There are several procedures under here, each of which
  1336.  *    mirrors an existing X procedure.  In addition to performing
  1337.  *    the functions of the corresponding procedure, each
  1338.  *    procedure also updates the local window structure and
  1339.  *    synthesizes an X event (if the window's structure is being
  1340.  *    managed internally).
  1341.  *
  1342.  * Results:
  1343.  *    See the manual entries.
  1344.  *
  1345.  * Side effects:
  1346.  *    See the manual entries.
  1347.  *
  1348.  *--------------------------------------------------------------
  1349.  */
  1350.  
  1351. void
  1352. Tk_UnmapWindow(tkwin)
  1353.     Tk_Window tkwin;        /* Token for window to unmap. */
  1354. {
  1355.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1356.  
  1357.     if (!(winPtr->flags & TK_MAPPED) || (winPtr->flags & TK_ALREADY_DEAD)) {
  1358.     return;
  1359.     }
  1360.     if (winPtr->flags & TK_TOP_LEVEL) {
  1361.     /*
  1362.      * Special processing has to be done for top-level windows.  Let
  1363.      * tkWm.c handle everything itself.
  1364.      */
  1365.  
  1366.     TkWmUnmapWindow(winPtr);
  1367.     return;
  1368.     }
  1369.     winPtr->flags &= ~TK_MAPPED;
  1370.     XUnmapWindow(winPtr->display, winPtr->window);
  1371.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1372.     XEvent event;
  1373.  
  1374.     event.type = UnmapNotify;
  1375.     event.xunmap.serial = LastKnownRequestProcessed(winPtr->display);
  1376.     event.xunmap.send_event = False;
  1377.     event.xunmap.display = winPtr->display;
  1378.     event.xunmap.event = winPtr->window;
  1379.     event.xunmap.window = winPtr->window;
  1380.     event.xunmap.from_configure = False;
  1381.     Tk_HandleEvent(&event);
  1382.     }
  1383. }
  1384.  
  1385. void
  1386. Tk_ConfigureWindow(tkwin, valueMask, valuePtr)
  1387.     Tk_Window tkwin;        /* Window to re-configure. */
  1388.     unsigned int valueMask;    /* Mask indicating which parts of
  1389.                  * *valuePtr are to be used. */
  1390.     XWindowChanges *valuePtr;    /* New values. */
  1391. {
  1392.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1393.  
  1394.     if (valueMask & CWX) {
  1395.     winPtr->changes.x = valuePtr->x;
  1396.     }
  1397.     if (valueMask & CWY) {
  1398.     winPtr->changes.y = valuePtr->y;
  1399.     }
  1400.     if (valueMask & CWWidth) {
  1401.     winPtr->changes.width = valuePtr->width;
  1402.     }
  1403.     if (valueMask & CWHeight) {
  1404.     winPtr->changes.height = valuePtr->height;
  1405.     }
  1406.     if (valueMask & CWBorderWidth) {
  1407.     winPtr->changes.border_width = valuePtr->border_width;
  1408.     }
  1409.     if (valueMask & (CWSibling|CWStackMode)) {
  1410.     panic("Can't set sibling or stack mode from Tk_ConfigureWindow.");
  1411.     }
  1412.  
  1413.     if (winPtr->window != None) {
  1414.     XConfigureWindow(winPtr->display, winPtr->window,
  1415.         valueMask, valuePtr);
  1416.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1417.         DoConfigureNotify(winPtr);
  1418.     }
  1419.     } else {
  1420.     winPtr->dirtyChanges |= valueMask;
  1421.     winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
  1422.     }
  1423. }
  1424.  
  1425. void
  1426. Tk_MoveWindow(tkwin, x, y)
  1427.     Tk_Window tkwin;        /* Window to move. */
  1428.     int x, y;            /* New location for window (within
  1429.                  * parent). */
  1430. {
  1431.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1432.  
  1433.     winPtr->changes.x = x;
  1434.     winPtr->changes.y = y;
  1435.     if (winPtr->window != None) {
  1436.     XMoveWindow(winPtr->display, winPtr->window, x, y);
  1437.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1438.         DoConfigureNotify(winPtr);
  1439.     }
  1440.     } else {
  1441.     winPtr->dirtyChanges |= CWX|CWY;
  1442.     winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
  1443.     }
  1444. }
  1445.  
  1446. void
  1447. Tk_ResizeWindow(tkwin, width, height)
  1448.     Tk_Window tkwin;        /* Window to resize. */
  1449.     int width, height;        /* New dimensions for window. */
  1450. {
  1451.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1452.  
  1453.     winPtr->changes.width = (unsigned) width;
  1454.     winPtr->changes.height = (unsigned) height;
  1455.     if (winPtr->window != None) {
  1456.     XResizeWindow(winPtr->display, winPtr->window, (unsigned) width,
  1457.         (unsigned) height);
  1458.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1459.         DoConfigureNotify(winPtr);
  1460.     }
  1461.     } else {
  1462.     winPtr->dirtyChanges |= CWWidth|CWHeight;
  1463.     winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
  1464.     }
  1465. }
  1466.  
  1467. void
  1468. Tk_MoveResizeWindow(tkwin, x, y, width, height)
  1469.     Tk_Window tkwin;        /* Window to move and resize. */
  1470.     int x, y;            /* New location for window (within
  1471.                  * parent). */
  1472.     int width, height;        /* New dimensions for window. */
  1473. {
  1474.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1475.  
  1476.     winPtr->changes.x = x;
  1477.     winPtr->changes.y = y;
  1478.     winPtr->changes.width = (unsigned) width;
  1479.     winPtr->changes.height = (unsigned) height;
  1480.     if (winPtr->window != None) {
  1481.     XMoveResizeWindow(winPtr->display, winPtr->window, x, y,
  1482.         (unsigned) width, (unsigned) height);
  1483.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1484.         DoConfigureNotify(winPtr);
  1485.     }
  1486.     } else {
  1487.     winPtr->dirtyChanges |= CWX|CWY|CWWidth|CWHeight;
  1488.     winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
  1489.     }
  1490. }
  1491.  
  1492. void
  1493. Tk_SetWindowBorderWidth(tkwin, width)
  1494.     Tk_Window tkwin;        /* Window to modify. */
  1495.     int width;            /* New border width for window. */
  1496. {
  1497.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1498.  
  1499.     winPtr->changes.border_width = width;
  1500.     if (winPtr->window != None) {
  1501.     XSetWindowBorderWidth(winPtr->display, winPtr->window,
  1502.         (unsigned) width);
  1503.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1504.         DoConfigureNotify(winPtr);
  1505.     }
  1506.     } else {
  1507.     winPtr->dirtyChanges |= CWBorderWidth;
  1508.     winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
  1509.     }
  1510. }
  1511.  
  1512. void
  1513. Tk_ChangeWindowAttributes(tkwin, valueMask, attsPtr)
  1514.     Tk_Window tkwin;        /* Window to manipulate. */
  1515.     unsigned long valueMask;    /* OR'ed combination of bits,
  1516.                  * indicating which fields of
  1517.                  * *attsPtr are to be used. */
  1518.     register XSetWindowAttributes *attsPtr;
  1519.                 /* New values for some attributes. */
  1520. {
  1521.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1522.  
  1523.     if (valueMask & CWBackPixmap) {
  1524.     winPtr->atts.background_pixmap = attsPtr->background_pixmap;
  1525.     }
  1526.     if (valueMask & CWBackPixel) {
  1527.     winPtr->atts.background_pixel = attsPtr->background_pixel;
  1528.     }
  1529.     if (valueMask & CWBorderPixmap) {
  1530.     winPtr->atts.border_pixmap = attsPtr->border_pixmap;
  1531.     }
  1532.     if (valueMask & CWBorderPixel) {
  1533.     winPtr->atts.border_pixel = attsPtr->border_pixel;
  1534.     }
  1535.     if (valueMask & CWBitGravity) {
  1536.     winPtr->atts.bit_gravity = attsPtr->bit_gravity;
  1537.     }
  1538.     if (valueMask & CWWinGravity) {
  1539.     winPtr->atts.win_gravity = attsPtr->win_gravity;
  1540.     }
  1541.     if (valueMask & CWBackingStore) {
  1542.     winPtr->atts.backing_store = attsPtr->backing_store;
  1543.     }
  1544.     if (valueMask & CWBackingPlanes) {
  1545.     winPtr->atts.backing_planes = attsPtr->backing_planes;
  1546.     }
  1547.     if (valueMask & CWBackingPixel) {
  1548.     winPtr->atts.backing_pixel = attsPtr->backing_pixel;
  1549.     }
  1550.     if (valueMask & CWOverrideRedirect) {
  1551.     winPtr->atts.override_redirect = attsPtr->override_redirect;
  1552.     }
  1553.     if (valueMask & CWSaveUnder) {
  1554.     winPtr->atts.save_under = attsPtr->save_under;
  1555.     }
  1556.     if (valueMask & CWEventMask) {
  1557.     winPtr->atts.event_mask = attsPtr->event_mask;
  1558.     }
  1559.     if (valueMask & CWDontPropagate) {
  1560.     winPtr->atts.do_not_propagate_mask
  1561.         = attsPtr->do_not_propagate_mask;
  1562.     }
  1563.     if (valueMask & CWColormap) {
  1564.     winPtr->atts.colormap = attsPtr->colormap;
  1565.     }
  1566.     if (valueMask & CWCursor) {
  1567.     winPtr->atts.cursor = attsPtr->cursor;
  1568.     }
  1569.  
  1570.     if (winPtr->window != None) {
  1571.     XChangeWindowAttributes(winPtr->display, winPtr->window,
  1572.         valueMask, attsPtr);
  1573.     } else {
  1574.     winPtr->dirtyAtts |= valueMask;
  1575.     }
  1576. }
  1577.  
  1578. void
  1579. Tk_SetWindowBackground(tkwin, pixel)
  1580.     Tk_Window tkwin;        /* Window to manipulate. */
  1581.     unsigned long pixel;    /* Pixel value to use for
  1582.                  * window's background. */
  1583. {
  1584.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1585.  
  1586.     winPtr->atts.background_pixel = pixel;
  1587.  
  1588.     if (winPtr->window != None) {
  1589.     XSetWindowBackground(winPtr->display, winPtr->window, pixel);
  1590.     } else {
  1591.     winPtr->dirtyAtts = (winPtr->dirtyAtts & (unsigned) ~CWBackPixmap)
  1592.         | CWBackPixel;
  1593.     }
  1594. }
  1595.  
  1596. void
  1597. Tk_SetWindowBackgroundPixmap(tkwin, pixmap)
  1598.     Tk_Window tkwin;        /* Window to manipulate. */
  1599.     Pixmap pixmap;        /* Pixmap to use for window's
  1600.                  * background. */
  1601. {
  1602.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1603.  
  1604.     winPtr->atts.background_pixmap = pixmap;
  1605.  
  1606.     if (winPtr->window != None) {
  1607.     XSetWindowBackgroundPixmap(winPtr->display,
  1608.         winPtr->window, pixmap);
  1609.     } else {
  1610.     winPtr->dirtyAtts = (winPtr->dirtyAtts & (unsigned) ~CWBackPixel)
  1611.         | CWBackPixmap;
  1612.     }
  1613. }
  1614.  
  1615. void
  1616. Tk_SetWindowBorder(tkwin, pixel)
  1617.     Tk_Window tkwin;        /* Window to manipulate. */
  1618.     unsigned long pixel;    /* Pixel value to use for
  1619.                  * window's border. */
  1620. {
  1621.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1622.  
  1623.     winPtr->atts.border_pixel = pixel;
  1624.  
  1625.     if (winPtr->window != None) {
  1626.     XSetWindowBorder(winPtr->display, winPtr->window, pixel);
  1627.     } else {
  1628.     winPtr->dirtyAtts = (winPtr->dirtyAtts & (unsigned) ~CWBorderPixmap)
  1629.         | CWBorderPixel;
  1630.     }
  1631. }
  1632.  
  1633. void
  1634. Tk_SetWindowBorderPixmap(tkwin, pixmap)
  1635.     Tk_Window tkwin;        /* Window to manipulate. */
  1636.     Pixmap pixmap;        /* Pixmap to use for window's
  1637.                  * border. */
  1638. {
  1639.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1640.  
  1641.     winPtr->atts.border_pixmap = pixmap;
  1642.  
  1643.     if (winPtr->window != None) {
  1644.     XSetWindowBorderPixmap(winPtr->display,
  1645.         winPtr->window, pixmap);
  1646.     } else {
  1647.     winPtr->dirtyAtts = (winPtr->dirtyAtts & (unsigned) ~CWBorderPixel)
  1648.         | CWBorderPixmap;
  1649.     }
  1650. }
  1651.  
  1652. void
  1653. Tk_DefineCursor(tkwin, cursor)
  1654.     Tk_Window tkwin;        /* Window to manipulate. */
  1655.     Cursor cursor;        /* Cursor to use for window (may be None). */
  1656. {
  1657.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1658.  
  1659.     winPtr->atts.cursor = cursor;
  1660.  
  1661.     if (winPtr->window != None) {
  1662.     XDefineCursor(winPtr->display, winPtr->window, cursor);
  1663.     } else {
  1664.     winPtr->dirtyAtts = winPtr->dirtyAtts | CWCursor;
  1665.     }
  1666. }
  1667.  
  1668. void
  1669. Tk_UndefineCursor(tkwin)
  1670.     Tk_Window tkwin;        /* Window to manipulate. */
  1671. {
  1672.     Tk_DefineCursor(tkwin, None);
  1673. }
  1674.  
  1675. void
  1676. Tk_SetWindowColormap(tkwin, colormap)
  1677.     Tk_Window tkwin;        /* Window to manipulate. */
  1678.     Colormap colormap;        /* Colormap to use for window. */
  1679. {
  1680.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1681.  
  1682.     winPtr->atts.colormap = colormap;
  1683.  
  1684.     if (winPtr->window != None) {
  1685.     XSetWindowColormap(winPtr->display, winPtr->window, colormap);
  1686.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1687.         TkWmAddToColormapWindows(winPtr);
  1688.     }
  1689.     } else {
  1690.     winPtr->dirtyAtts |= CWColormap;
  1691.     }
  1692. }
  1693.  
  1694. /*
  1695.  *----------------------------------------------------------------------
  1696.  *
  1697.  * Tk_SetWindowVisual --
  1698.  *
  1699.  *    This procedure is called to specify a visual to be used
  1700.  *    for a Tk window when it is created.  This procedure, if
  1701.  *    called at all, must be called before the X window is created
  1702.  *    (i.e. before Tk_MakeWindowExist is called).
  1703.  *
  1704.  * Results:
  1705.  *    The return value is 1 if successful, or 0 if the X window has
  1706.  *    been already created.
  1707.  *
  1708.  * Side effects:
  1709.  *    The information given is stored for when the window is created.
  1710.  *
  1711.  *----------------------------------------------------------------------
  1712.  */
  1713.  
  1714. int
  1715. Tk_SetWindowVisual(tkwin, visual, depth, colormap)
  1716.     Tk_Window tkwin;        /* Window to manipulate. */
  1717.     Visual *visual;        /* New visual for window. */
  1718.     int depth;            /* New depth for window. */
  1719.     Colormap colormap;        /* An appropriate colormap for the visual. */
  1720. {
  1721.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1722.  
  1723.     if( winPtr->window != None ){
  1724.     /* Too late! */
  1725.     return 0;
  1726.     }
  1727.  
  1728.     winPtr->visual = visual;
  1729.     winPtr->depth = depth;
  1730.     winPtr->atts.colormap = colormap;
  1731.  
  1732.     /*
  1733.      * The following code is needed to make sure that the window doesn't
  1734.      * inherit the parent's border pixmap, which would result in a BadMatch
  1735.      * error.
  1736.      */
  1737.  
  1738.     if (!(winPtr->dirtyAtts & CWBorderPixmap)) {
  1739.     winPtr->dirtyAtts |= CWBorderPixel;
  1740.     }
  1741.     return 1;
  1742. }
  1743.  
  1744. /*
  1745.  *----------------------------------------------------------------------
  1746.  *
  1747.  * DoConfigureNotify --
  1748.  *
  1749.  *    Generate a ConfigureNotify event describing the current
  1750.  *    configuration of a window.
  1751.  *
  1752.  * Results:
  1753.  *    None.
  1754.  *
  1755.  * Side effects:
  1756.  *    An event is generated and processed by Tk_HandleEvent.
  1757.  *
  1758.  *----------------------------------------------------------------------
  1759.  */
  1760.  
  1761. static void
  1762. DoConfigureNotify(winPtr)
  1763.     register TkWindow *winPtr;        /* Window whose configuration
  1764.                      * was just changed. */
  1765. {
  1766.     XEvent event;
  1767.  
  1768.     event.type = ConfigureNotify;
  1769.     event.xconfigure.serial = LastKnownRequestProcessed(winPtr->display);
  1770.     event.xconfigure.send_event = False;
  1771.     event.xconfigure.display = winPtr->display;
  1772.     event.xconfigure.event = winPtr->window;
  1773.     event.xconfigure.window = winPtr->window;
  1774.     event.xconfigure.x = winPtr->changes.x;
  1775.     event.xconfigure.y = winPtr->changes.y;
  1776.     event.xconfigure.width = winPtr->changes.width;
  1777.     event.xconfigure.height = winPtr->changes.height;
  1778.     event.xconfigure.border_width = winPtr->changes.border_width;
  1779.     if (winPtr->changes.stack_mode == Above) {
  1780.     event.xconfigure.above = winPtr->changes.sibling;
  1781.     } else {
  1782.     event.xconfigure.above = None;
  1783.     }
  1784.     event.xconfigure.override_redirect = winPtr->atts.override_redirect;
  1785.     Tk_HandleEvent(&event);
  1786. }
  1787.  
  1788. /*
  1789.  *----------------------------------------------------------------------
  1790.  *
  1791.  * Tk_SetClass --
  1792.  *
  1793.  *    This procedure is used to give a window a class.
  1794.  *
  1795.  * Results:
  1796.  *    None.
  1797.  *
  1798.  * Side effects:
  1799.  *    A new class is stored for tkwin, replacing any existing
  1800.  *    class for it.
  1801.  *
  1802.  *----------------------------------------------------------------------
  1803.  */
  1804.  
  1805. void
  1806. Tk_SetClass(tkwin, className)
  1807.     Tk_Window tkwin;        /* Token for window to assign class. */
  1808.     char *className;        /* New class for tkwin. */
  1809. {
  1810.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1811.  
  1812.     winPtr->classUid = Tk_GetUid(className);
  1813.     if (winPtr->flags & TK_TOP_LEVEL) {
  1814.     TkWmSetClass(winPtr);
  1815.     }
  1816.     TkOptionClassChanged(winPtr);
  1817. }
  1818.  
  1819. /*
  1820.  *----------------------------------------------------------------------
  1821.  *
  1822.  * Tk_NameToWindow --
  1823.  *
  1824.  *    Given a string name for a window, this procedure
  1825.  *    returns the token for the window, if there exists a
  1826.  *    window corresponding to the given name.
  1827.  *
  1828.  * Results:
  1829.  *    The return result is either a token for the window corresponding
  1830.  *    to "name", or else NULL to indicate that there is no such
  1831.  *    window.  In this case, an error message is left in interp->result.
  1832.  *
  1833.  * Side effects:
  1834.  *    None.
  1835.  *
  1836.  *----------------------------------------------------------------------
  1837.  */
  1838.  
  1839. Tk_Window
  1840. Tk_NameToWindow(interp, pathName, tkwin)
  1841.     Tcl_Interp *interp;        /* Where to report errors. */
  1842.     char *pathName;        /* Path name of window. */
  1843.     Tk_Window tkwin;        /* Token for window:  name is assumed to
  1844.                  * belong to the same main window as tkwin. */
  1845. {
  1846.     Tcl_HashEntry *hPtr;
  1847.  
  1848.     hPtr = Tcl_FindHashEntry(&((TkWindow *) tkwin)->mainPtr->nameTable,
  1849.         pathName);
  1850.     if (hPtr == NULL) {
  1851.     Tcl_AppendResult(interp, "bad window path name \"",
  1852.         pathName, "\"", (char *) NULL);
  1853.     return NULL;
  1854.     }
  1855.     return (Tk_Window) Tcl_GetHashValue(hPtr);
  1856. }
  1857.  
  1858. /*
  1859.  *----------------------------------------------------------------------
  1860.  *
  1861.  * Tk_IdToWindow --
  1862.  *
  1863.  *    Given an X display and window ID, this procedure returns the
  1864.  *    Tk token for the window, if there exists a Tk window corresponding
  1865.  *    to the given ID.
  1866.  *
  1867.  * Results:
  1868.  *    The return result is either a token for the window corresponding
  1869.  *    to the given X id, or else NULL to indicate that there is no such
  1870.  *    window.
  1871.  *
  1872.  * Side effects:
  1873.  *    None.
  1874.  *
  1875.  *----------------------------------------------------------------------
  1876.  */
  1877.  
  1878. Tk_Window
  1879. Tk_IdToWindow(display, window)
  1880.     Display *display;        /* X display containing the window. */
  1881.     Window window;        /* X window window id. */
  1882. {
  1883.     TkDisplay *dispPtr;
  1884.     Tcl_HashEntry *hPtr;
  1885.  
  1886.     for (dispPtr = tkDisplayList; ; dispPtr = dispPtr->nextPtr) {
  1887.     if (dispPtr == NULL) {
  1888.         return NULL;
  1889.     }
  1890.     if (dispPtr->display == display) {
  1891.         break;
  1892.     }
  1893.     }
  1894.  
  1895.     hPtr = Tcl_FindHashEntry(&dispPtr->winTable, (char *) window);
  1896.     if (hPtr == NULL) {
  1897.     return NULL;
  1898.     }
  1899.     return (Tk_Window) Tcl_GetHashValue(hPtr);
  1900. }
  1901.  
  1902. /*
  1903.  *----------------------------------------------------------------------
  1904.  *
  1905.  * Tk_DisplayName --
  1906.  *
  1907.  *    Return the textual name of a window's display.
  1908.  *
  1909.  * Results:
  1910.  *    The return value is the string name of the display associated
  1911.  *    with tkwin.
  1912.  *
  1913.  * Side effects:
  1914.  *    None.
  1915.  *
  1916.  *----------------------------------------------------------------------
  1917.  */
  1918.  
  1919. char *
  1920. Tk_DisplayName(tkwin)
  1921.     Tk_Window tkwin;        /* Window whose display name is desired. */
  1922. {
  1923.     return ((TkWindow *) tkwin)->dispPtr->name;
  1924. }
  1925.  
  1926. /*
  1927.  *----------------------------------------------------------------------
  1928.  *
  1929.  * UnlinkWindow --
  1930.  *
  1931.  *    This procedure removes a window from the childList of its
  1932.  *    parent.
  1933.  *
  1934.  * Results:
  1935.  *    None.
  1936.  *
  1937.  * Side effects:
  1938.  *    The window is unlinked from its childList.
  1939.  *
  1940.  *----------------------------------------------------------------------
  1941.  */
  1942.  
  1943. static void
  1944. UnlinkWindow(winPtr)
  1945.     TkWindow *winPtr;            /* Child window to be unlinked. */
  1946. {
  1947.     TkWindow *prevPtr;
  1948.  
  1949.     if (winPtr->parentPtr == NULL) {
  1950.     return;
  1951.     }
  1952.     prevPtr = winPtr->parentPtr->childList;
  1953.     if (prevPtr == winPtr) {
  1954.     winPtr->parentPtr->childList = winPtr->nextPtr;
  1955.     if (winPtr->nextPtr == NULL) {
  1956.         winPtr->parentPtr->lastChildPtr = NULL;
  1957.     }
  1958.     } else {
  1959.     while (prevPtr->nextPtr != winPtr) {
  1960.         prevPtr = prevPtr->nextPtr;
  1961.         if (prevPtr == NULL) {
  1962.         panic("UnlinkWindow couldn't find child in parent");
  1963.         }
  1964.     }
  1965.     prevPtr->nextPtr = winPtr->nextPtr;
  1966.     if (winPtr->nextPtr == NULL) {
  1967.         winPtr->parentPtr->lastChildPtr = prevPtr;
  1968.     }
  1969.     }
  1970. }
  1971.  
  1972. /*
  1973.  *----------------------------------------------------------------------
  1974.  *
  1975.  * Tk_RestackWindow --
  1976.  *
  1977.  *    Change a window's position in the stacking order.
  1978.  *
  1979.  * Results:
  1980.  *    TCL_OK is normally returned.  If other is not a descendant
  1981.  *    of tkwin's parent then TCL_ERROR is returned and tkwin is
  1982.  *    not repositioned.
  1983.  *
  1984.  * Side effects:
  1985.  *    Tkwin is repositioned in the stacking order.
  1986.  *
  1987.  *----------------------------------------------------------------------
  1988.  */
  1989.  
  1990. int
  1991. Tk_RestackWindow(tkwin, aboveBelow, other)
  1992.     Tk_Window tkwin;        /* Token for window whose position in
  1993.                  * the stacking order is to change. */
  1994.     int aboveBelow;        /* Indicates new position of tkwin relative
  1995.                  * to other;  must be Above or Below. */
  1996.     Tk_Window other;        /* Tkwin will be moved to a position that
  1997.                  * puts it just above or below this window.
  1998.                  * If NULL then tkwin goes above or below
  1999.                  * all windows in the same parent. */
  2000. {
  2001.     TkWindow *winPtr = (TkWindow *) tkwin;
  2002.     TkWindow *otherPtr = (TkWindow *) other;
  2003.     XWindowChanges changes;
  2004.     unsigned int mask;
  2005.  
  2006.  
  2007.     /*
  2008.      * Special case:  if winPtr is a top-level window then just find
  2009.      * the top-level ancestor of otherPtr and restack winPtr above
  2010.      * otherPtr without changing any of Tk's childLists.
  2011.      */
  2012.  
  2013.     changes.stack_mode = aboveBelow;
  2014.     mask = CWStackMode;
  2015.     if (winPtr->flags & TK_TOP_LEVEL) {
  2016.     while ((otherPtr != NULL) && !(otherPtr->flags & TK_TOP_LEVEL)) {
  2017.         otherPtr = otherPtr->parentPtr;
  2018.     }
  2019.     TkWmRestackToplevel(winPtr, aboveBelow, otherPtr);
  2020.     return TCL_OK;
  2021.     }
  2022.  
  2023.     /*
  2024.      * Find an ancestor of otherPtr that is a sibling of winPtr.
  2025.      */
  2026.  
  2027.     if (winPtr->parentPtr == NULL) {
  2028.     /*
  2029.      * Window is going to be deleted shortly;  don't do anything.
  2030.      */
  2031.  
  2032.     return TCL_OK;
  2033.     }
  2034.     if (otherPtr == NULL) {
  2035.     if (aboveBelow == Above) {
  2036.         otherPtr = winPtr->parentPtr->lastChildPtr;
  2037.     } else {
  2038.         otherPtr = winPtr->parentPtr->childList;
  2039.     }
  2040.     } else {
  2041.     while (winPtr->parentPtr != otherPtr->parentPtr) {
  2042.         if ((otherPtr == NULL) || (otherPtr->flags & TK_TOP_LEVEL)) {
  2043.         return TCL_ERROR;
  2044.         }
  2045.         otherPtr = otherPtr->parentPtr;
  2046.     }
  2047.     }
  2048.     if (otherPtr == winPtr) {
  2049.     return TCL_OK;
  2050.     }
  2051.  
  2052.     /*
  2053.      * Reposition winPtr in the stacking order.
  2054.      */
  2055.  
  2056.     UnlinkWindow(winPtr);
  2057.     if (aboveBelow == Above) {
  2058.     winPtr->nextPtr = otherPtr->nextPtr;
  2059.     if (winPtr->nextPtr == NULL) {
  2060.         winPtr->parentPtr->lastChildPtr = winPtr;
  2061.     }
  2062.     otherPtr->nextPtr = winPtr;
  2063.     } else {
  2064.     TkWindow *prevPtr;
  2065.  
  2066.     prevPtr = winPtr->parentPtr->childList;
  2067.     if (prevPtr == otherPtr) {
  2068.         winPtr->parentPtr->childList = winPtr;
  2069.     } else {
  2070.         while (prevPtr->nextPtr != otherPtr) {
  2071.         prevPtr = prevPtr->nextPtr;
  2072.         }
  2073.         prevPtr->nextPtr = winPtr;
  2074.     }
  2075.     winPtr->nextPtr = otherPtr;
  2076.     }
  2077.  
  2078.     /*
  2079.      * Notify the X server of the change.  If winPtr hasn't yet been
  2080.      * created then there's no need to tell the X server now, since
  2081.      * the stacking order will be handled properly when the window
  2082.      * is finally created.
  2083.      */
  2084.  
  2085.     if (winPtr->window != None) {
  2086.     changes.stack_mode = Above;
  2087.     for (otherPtr = winPtr->nextPtr; otherPtr != NULL;
  2088.         otherPtr = otherPtr->nextPtr) {
  2089.         if ((otherPtr->window != None)
  2090.             && !(otherPtr->flags & TK_TOP_LEVEL)){
  2091.         changes.sibling = otherPtr->window;
  2092.         changes.stack_mode = Below;
  2093.         mask = CWStackMode|CWSibling;
  2094.         break;
  2095.         }
  2096.     }
  2097.     XConfigureWindow(winPtr->display, winPtr->window, mask, &changes);
  2098.     }
  2099.     return TCL_OK;
  2100. }
  2101.  
  2102. /*
  2103.  *----------------------------------------------------------------------
  2104.  *
  2105.  * Tk_MainWindow --
  2106.  *
  2107.  *    Returns the main window for an application.
  2108.  *
  2109.  * Results:
  2110.  *    If interp has a Tk application associated with it, the main
  2111.  *    window for the application is returned.  Otherwise NULL is
  2112.  *    returned and an error message is left in interp->result.
  2113.  *
  2114.  * Side effects:
  2115.  *    None.
  2116.  *
  2117.  *----------------------------------------------------------------------
  2118.  */
  2119.  
  2120. Tk_Window
  2121. Tk_MainWindow(interp)
  2122.     Tcl_Interp *interp;            /* Interpreter that embodies the
  2123.                      * application.  Used for error
  2124.                      * reporting also. */
  2125. {
  2126.     TkMainInfo *mainPtr;
  2127.  
  2128.     for (mainPtr = tkMainWindowList; mainPtr != NULL;
  2129.         mainPtr = mainPtr->nextPtr) {
  2130.     if (mainPtr->interp == interp) {
  2131.         return (Tk_Window) mainPtr->winPtr;
  2132.     }
  2133.     }
  2134.     interp->result = "this isn't a Tk application";
  2135.     return NULL;
  2136. }
  2137.  
  2138. /*
  2139.  *----------------------------------------------------------------------
  2140.  *
  2141.  * Tk_StrictMotif --
  2142.  *
  2143.  *    Indicates whether strict Motif compliance has been specified
  2144.  *    for the given window.
  2145.  *
  2146.  * Results:
  2147.  *    The return value is 1 if strict Motif compliance has been
  2148.  *    requested for tkwin's application by setting the tk_strictMotif
  2149.  *    variable in its interpreter to a true value.  0 is returned
  2150.  *    if tk_strictMotif has a false value.
  2151.  *
  2152.  * Side effects:
  2153.  *    None.
  2154.  *
  2155.  *----------------------------------------------------------------------
  2156.  */
  2157.  
  2158. int
  2159. Tk_StrictMotif(tkwin)
  2160.     Tk_Window tkwin;            /* Window whose application is
  2161.                      * to be checked. */
  2162. {
  2163.     return ((TkWindow *) tkwin)->mainPtr->strictMotif;
  2164. }
  2165.  
  2166. /* 
  2167.  *--------------------------------------------------------------
  2168.  *
  2169.  * OpenIM --
  2170.  *
  2171.  *    Tries to open an X input method, associated with the
  2172.  *    given display.  Right now we can only deal with a bare-bones
  2173.  *    input style:  no preedit, and no status.
  2174.  *
  2175.  * Results:
  2176.  *    Stores the input method in dispPtr->inputMethod;  if there isn't
  2177.  *    a suitable input method, then NULL is stored in dispPtr->inputMethod.
  2178.  *
  2179.  * Side effects:
  2180.  *    An input method gets opened.
  2181.  *
  2182.  *--------------------------------------------------------------
  2183.  */
  2184.  
  2185. static void
  2186. OpenIM(dispPtr)
  2187.     TkDisplay *dispPtr;        /* Tk's structure for the display. */
  2188. {
  2189. #ifndef TK_USE_INPUT_METHODS
  2190.     return;
  2191. #else
  2192.     int i;
  2193.     XIMStyles *stylePtr;
  2194.  
  2195.     dispPtr->inputMethod = XOpenIM(dispPtr->display, NULL, NULL, NULL);
  2196.     if (dispPtr->inputMethod == NULL) {
  2197.     return;
  2198.     }
  2199.  
  2200.     if ((XGetIMValues(dispPtr->inputMethod, XNQueryInputStyle, &stylePtr,
  2201.         NULL) != NULL) || (stylePtr == NULL)) {
  2202.     goto error;
  2203.     }
  2204.     for (i = 0; i < stylePtr->count_styles; i++) {
  2205.     if (stylePtr->supported_styles[i]
  2206.         == (XIMPreeditNothing|XIMStatusNothing)) {
  2207.         XFree(stylePtr);
  2208.         return;
  2209.     }
  2210.     }
  2211.     XFree(stylePtr);
  2212.  
  2213.     error:
  2214.  
  2215.     /*
  2216.      * Should close the input method, but this causes core dumps on some
  2217.      * systems (e.g. Solaris 2.3 as of 1/6/95).
  2218.      * XCloseIM(dispPtr->inputMethod);
  2219.      */
  2220.     dispPtr->inputMethod = NULL;
  2221.     return;
  2222. #endif /* TK_USE_INPUT_METHODS */
  2223. }
  2224.